#ifndef AGBMUSIC_H__
#define AGBMUSIC_H__

#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef int8_t  s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;

typedef struct {
    u8 d[80];
} MusicPlayerTrack;

typedef struct {
    u16 type;   //Type
                //这些数据表明一个类型。这是目前使用的需要。
                //总是0x0000
    u16 stat;   //Status
                //目前,非循环(1)的波形是0x0000和正向循环0x40000
                //如果循环波形0x4000，如果1次波形值0x0000
    u32 freq;   //Frequency Calculation Value
                //这个值是用来计算频率,他是由以下公式计算 sampling rate * 2^((180 - (midi键<基础键，默认为60>))/12)
    u32 loop;   //Loop Start Point
                //循环的指针(循环开始)
                //循环的位置计算从采样数据的开始
    u32 size;   //Sampling Number
                //样本数（结束位置）
    s8 data[1]; //Sampling Data Order
                //实际波形数据,以(样本数+1)字节的8bit有符号线性非压缩的数据,最后一个字节是非循环波形的0,和相同的值作为一个循环波形指针数据
                //
} WaveData;

typedef struct {
    //0x0
	/*
	typ:
		0	乐器采样频率会随着mid而改变
		8	不会随着mid键而改变采样频率
	att:默认(0xff)
	dec:衰减值(0)
	sus:持续值(ff)
	rel:释放值(e2)

	att会被设置为 ch[9]
	ch 为SoundChannel 结构体

	但按下note的时候，会把Nxx设置到ch[0x10]中
		ch[0x10]为释放tick时间 (这个时间跟Wxx的时间是一样的)

	持续一段时间后，当ch[0x10]==0时，
		ch[0]被设置为释放（relese）状态
		每帧执行一次
			ch[9] = (ch[9] * rel)>>8

	ch[9] 为音量

	也就是说，但Note抬起时(Nxx时间后),执行处理
		ch[9] = (ch[9] * rel)>>8

	att,dec,sus三者关系
	当按下att时，会进行一个dec过程，直到音量维持在sus，抬起时，再处理rel




	*/
    u8 typ;         //Type                                      类型

    u8 key;         //Original Key                              原始的键
                    //
    u8 len;         //Sound Length (Compatible Sound)           声音的长度（兼容的声音）
    u8 p_s;         //Pan or Sweep (Compatible Sound 1)
    WaveData *wav;  //Wave Data Address                         wave地址
    u8 att;         //Attack                                    打击
    u8 dec;         //Decay                                     衰变
    u8 sus;         //Sustain                                   维持
    u8 rel;         //Release                                   释放
} ToneData;



typedef struct {
    struct SongHeader *song;   //Current Song Pointer  当前歌曲指针
    u32 stat;           //Status            状态
    u8 mtrk;            //Track Number      磁道数
    u8 prio;            //Current Priority  当前优先权
    u8 d1[2];
    u32 clock;          //Calculation Clock from Performance Start 时钟开始计算性能
    u8 d2[48];			//:0x10+32  = 0x42
} MusicPlayerArea;

typedef struct {
    MusicPlayerArea *ma;
    MusicPlayerTrack *ta;
    u32 tn;
} MPlayTable;

typedef struct{
	/*
	0x80的时候，会从
	data(ToneDataArr)那查找音色,并且不会改变声音频率

	*/
    u8  type;   //0x80;
    u8  z1,z2,z3;
    ToneData *data;
    u32 base_note;
}_0x80;

typedef struct {
	/*
	0x40会随着mid而更改采样频率

	*/
    u32 typ /*0x40*/;
    //ToneData *ta;       //应该是ToneDataArr
    union ToneDataArr *ta;
/*键对应的音色索引,
[0]=0
[1]=0
表示 C1, C#1 对应第0个音色
[2]=1
[3]=1
表示 D1, D#1 对应第1个音色
*/
u8 *st;

} SplitTone;
typedef union ToneDataArr{ ToneData t; SplitTone s; _0x80 ref; } ToneDataArr;

typedef struct SongHeader{
    u8 trks;            //Track Number 磁道数
    u8 blks;            //Block Number 块编号
    u8 prio;            //Priority 优先权
    u8 rvrb;            //Reverb  混响
    //ToneData *tone;     //Tone Table 音表
    ToneDataArr *tone;
    u8 *part[1];
} SongHeader;

typedef struct {
    SongHeader *so;
    /*ms表示使用播放器索引*/
    u16 ms, me;
} SongTable;

/*
类型,
0x00:表示采样文件
0x40:表示slpt
0x08:固定间隔(Interval fixed),不会根据key更改频率
0x80:节奏设置(Rhythm set) ,引用其他ToneData*

;       type : A(0x00)                        Direct sound
;              F(0x01)                        Direct sound (Interval fixed)
;              P()                        CGB compatible sound (Interval preferred)
;              Q(0x10)                        CGB compatible sound (Tone color preferred)
;              R(0x80)                        Rhythm set
;              S(0x40)                        Key split tone color

*/
#define TONEDATA_TYP_RHY    0x80
#define TONEDATA_TYP_SPL    0x40
#define TONEDATA_TYP_FIX    0x08
#define TONEDATA_TYP_CGB    0x07


/*
定义
*/
#define W00 	0x80		/*WAIT */
#define W01 	(W00+1)
#define W02 	(W00+2)
#define W03 	(W00+3)
#define W04 	(W00+4)
#define W05 	(W00+5)
#define W06 	(W00+6)
#define W07 	(W00+7)
#define W08 	(W00+8)
#define W09 	(W00+9)
#define W10 	(W00+10)
#define W11 	(W00+11)
#define W12 	(W00+12)
#define W13 	(W00+13)
#define W14 	(W00+14)
#define W15 	(W00+15)
#define W16 	(W00+16)
#define W17 	(W00+17)
#define W18 	(W00+18)
#define W19 	(W00+19)
#define W20 	(W00+20)
#define W21 	(W00+21)
#define W22 	(W00+22)
#define W23 	(W00+23)
#define W24 	(W00+24)
#define W28 	(W00+25)
#define W30 	(W00+26)
#define W32 	(W00+27)
#define W36 	(W00+28)
#define W40 	(W00+29)
#define W42 	(W00+30)
#define W44 	(W00+31)
#define W48 	(W00+32)
#define W52 	(W00+33)
#define W54 	(W00+34)
#define W56 	(W00+35)
#define W60 	(W00+36)
#define W64 	(W00+37)
#define W66 	(W00+38)
#define W68 	(W00+39)
#define W72 	(W00+40)
#define W76 	(W00+41)
#define W78 	(W00+42)
#define W80 	(W00+43)
#define W84 	(W00+44)
#define W88 	(W00+45)
#define W90 	(W00+46)
#define W92 	(W00+47)
#define W96 	(W00+48)
//fine
#define FINE 	0xb1
//goto								跳转
#define GOTO 	0xb2
//pattern play						格局播放
#define PATT 	0xb3
//pattern end						格局结束
#define PEND 	0xb4
//repeat	重复
#define REPT 	0xb5
//memacc op adr dat ***lib
#define MEMACC 	0xb9
//priority							优先级
#define PRIO 	0xba
//tempo (BPM/2)						节奏	(BPM/2)
#define TEMPO 	0xbb
//key shift							键变化
#define KEYSH 	0xbc


// voice #							声音
#define	VOICE	0xbd
// volume							音量
#define	VOL	0xbe
// panpot (c_v+??)
#define	PAN	0xbf
// pitch bend (c_v+??)				音高
#define	BEND	0xc0
// bend range						弯曲范围
/*
滑音范围，可以用(xm)
	Portamento up
	1xx 替代

8000A9C: [R5+9] 会作为MidiKey2fr的第3个参数

MusicPlayerTrack->d[0xf] = BENDR
*/

#define	BENDR	0xc1
// LFO speed							低频振荡速度
#define	LFOS	0xc2
// LFO delay							低频振荡衰减
#define	LFODL	0xc3
// modulation depth					调制深度
#define	MOD	0xc4
// modulation type					调制类型
#define	MODT	0xc5
// micro tuning (c_v+??)				微调
#define	TUNE	0xc8
#define _PORT    0xcc
// extend command  ***lib			扩展指令,库
#define	XCMD	0xcd
//  imi.echo vol   ***lib
#define	xIECV	0x08
//  imi.echo len   ***lib
#define	xIECL	0x09
// End of Tie
#define	EOT 	0xce
#define	TIE 	0xcf		//
// NOTE
#define	N01 	(TIE+1)
#define	N02 	(N01+1)		//
#define	N03 	(N01+2)		//
#define	N04 	(N01+3)		//
#define	N05 	(N01+4)		//
#define	N06 	(N01+5)		//
#define	N07 	(N01+6)		//
#define	N08 	(N01+7)		//
#define	N09 	(N01+8)		//
#define	N10 	(N01+9)		//
#define	N11 	(N01+10)		//
#define	N12 	(N01+11)		//
#define	N13 	(N01+12)		//
#define	N14 	(N01+13)		//
#define	N15 	(N01+14)		//
#define	N16 	(N01+15)		//
#define	N17 	(N01+16)		//
#define	N18 	(N01+17)		//
#define	N19 	(N01+18)		//
#define	N20 	(N01+19)		//
#define	N21 	(N01+20)		//
#define	N22 	(N01+21)		//
#define	N23 	(N01+22)		//
#define	N24 	(N01+23)		//
#define	N28 	(N01+24)		//
#define	N30 	(N01+25)		//
#define	N32 	(N01+26)		//
#define	N36 	(N01+27)		//
#define	N40 	(N01+28)		//
#define	N42 	(N01+29)		//
#define	N44 	(N01+30)		//
#define	N48 	(N01+31)		//
#define	N52 	(N01+32)		//
#define	N54 	(N01+33)		//
#define	N56 	(N01+34)		//
#define	N60 	(N01+35)		//
#define	N64 	(N01+36)		//
#define	N66 	(N01+37)		//
#define	N68 	(N01+38)		//
#define	N72 	(N01+39)		//
#define	N76 	(N01+40)		//
#define	N78 	(N01+41)		//
#define	N80 	(N01+42)		//
#define	N84 	(N01+43)		//
#define	N88 	(N01+44)		//
#define	N90 	(N01+45)		//
#define	N92 	(N01+46)		//
#define	N96 	(N01+47)		//

static const char* note_w_name[] = {
"N01","N02",	//
"N03",	//
"N04",	//
"N05",	//
"N06",	//
"N07",	//
"N08",	//
"N09",	//
"N10",	//
"N11",		//
"N12",		//
"N13",		//
"N14",		//
"N15",		//
"N16",		//
"N17",		//
"N18",		//
"N19",		//
"N20",		//
"N21",		//
"N22",		//
"N23",		//
"N24",		//
"N28",		//
"N30",		//
"N32",		//
"N36",		//
"N40",		//
"N42",		//
"N44",		//
"N48",		//
"N52",		//
"N54",		//
"N56",		//
"N60",		//
"N64",		//
"N66",		//
"N68",		//
"N72",		//
"N76",		//
"N78",		//
"N80",		//
"N84",		//
"N88",		//
"N90",		//
"N92",		//
"N96",		//
};

//Max value of operators	运算最大值
#define mxv	0x7F

//center value of PAN, BEND, TUNE
#define	c_v	0x40


	#define 	CnM2	0
	#define 	CsM2	1
	#define 	DnM2	2
	#define 	DsM2	3
	#define 	EnM2	4
	#define 	FnM2	5
	#define 	FsM2	6
	#define 	GnM2	7
	#define 	GsM2	8
	#define 	AnM2	9
	#define 	AsM2	10
	#define 	BnM2	11
	#define 	CnM1	12
	#define 	CsM1	13
	#define 	DnM1	14
	#define 	DsM1	15
	#define 	EnM1	16
	#define 	FnM1	17
	#define 	FsM1	18
	#define 	GnM1	19
	#define 	GsM1	20
	#define 	AnM1	21
	#define 	AsM1	22
	#define 	BnM1	23
	#define 	Cn0	24
	#define 	Cs0	25
	#define 	Dn0	26
	#define 	Ds0	27
	#define 	En0	28
	#define 	Fn0	29
	#define 	Fs0	30
	#define 	Gn0	31
	#define 	Gs0	32
	#define 	An0	33
	#define 	As0	34
	#define 	Bn0	35
	#define 	Cn1	36
	#define 	Cs1	37
	#define 	Dn1	38
	#define 	Ds1	39
	#define 	En1	40
	#define 	Fn1	41
	#define 	Fs1	42
	#define 	Gn1	43
	#define 	Gs1	44
	#define 	An1	45
	#define 	As1	46
	#define 	Bn1	47
	#define 	Cn2	48
	#define 	Cs2	49
	#define 	Dn2	50
	#define 	Ds2	51
	#define 	En2	52
	#define 	Fn2	53
	#define 	Fs2	54
	#define 	Gn2	55
	#define 	Gs2	56
	#define 	An2	57
	#define 	As2	58
	#define 	Bn2	59
	//默认的声音频率
	#define 	Cn3	60
	#define 	Cs3	61
	#define 	Dn3	62
	#define 	Ds3	63
	#define 	En3	64
	#define 	Fn3	65
	#define 	Fs3	66
	#define 	Gn3	67
	#define 	Gs3	68
    //440Hz
	#define 	An3	69
	#define 	As3	70
	#define 	Bn3	71
	#define 	Cn4	72
	#define 	Cs4	73
	#define 	Dn4	74
	#define 	Ds4	75
	#define 	En4	76
	#define 	Fn4	77
	#define 	Fs4	78
	#define 	Gn4	79
	#define 	Gs4	80
	#define 	An4	81
	#define 	As4	82
	#define 	Bn4	83
	#define 	Cn5	84
	#define 	Cs5	85
	#define 	Dn5	86
	#define 	Ds5	87
	#define 	En5	88
	#define 	Fn5	89
	#define 	Fs5	90
	#define 	Gn5	91
	#define 	Gs5	92
	#define 	An5	93
	#define 	As5	94
	#define 	Bn5	95
	#define 	Cn6	96
	#define 	Cs6	97
	#define 	Dn6	98
	#define 	Ds6	99
	#define 	En6	100
	#define 	Fn6	101
	#define 	Fs6	102
	#define 	Gn6	103
	#define 	Gs6	104
	#define 	An6	105
	#define 	As6	106
	#define 	Bn6	107
	#define 	Cn7	108
	#define 	Cs7	109
	#define 	Dn7	110
	#define 	Ds7	111
	#define 	En7	112
	#define 	Fn7	113
	#define 	Fs7	114
	#define 	Gn7	115
	#define 	Gs7	116
	#define 	An7	117
	#define 	As7	118
	#define 	Bn7	119
	#define 	Cn8	120
	#define 	Cs8	121
	#define 	Dn8	122
	#define 	Ds8	123
	#define 	En8	124
	#define 	Fn8	125
	#define 	Fs8	126
	#define 	Gn8	127

static const char* note_name[] = {
	"CnM2",
	"CsM2",
	"DnM2",
	"DsM2",
	"EnM2",
	"FnM2",
	"FsM2",
	"GnM2",
	"GsM2",
	"AnM2",
	"AsM2",
	"BnM2",
	"CnM1",
	"CsM1",
	"DnM1",
	"DsM1",
	"EnM1",
	"FnM1",
	"FsM1",
	"GnM1",
	"GsM1",
	"AnM1",
	"AsM1",
	"BnM1",
	"Cn0",
	"Cs0",
	"Dn0",
	"Ds0",
	"En0",
	"Fn0",
	"Fs0",
	"Gn0",
	"Gs0",
	"An0",
	"As0",
	"Bn0",
	"Cn1",
	"Cs1",
	"Dn1",
	"Ds1",
	"En1",
	"Fn1",
	"Fs1",
	"Gn1",
	"Gs1",
	"An1",
	"As1",
	"Bn1",
	"Cn2",
	"Cs2",
	"Dn2",
	"Ds2",
	"En2",
	"Fn2",
	"Fs2",
	"Gn2",
	"Gs2",
	"An2",
	"As2",
	"Bn2",
	"Cn3",
	"Cs3",
	"Dn3",
	"Ds3",
	"En3",
	"Fn3",
	"Fs3",
	"Gn3",
	"Gs3",
	"An3",
	"As3",
	"Bn3",
	"Cn4",
	"Cs4",
	"Dn4",
	"Ds4",
	"En4",
	"Fn4",
	"Fs4",
	"Gn4",
	"Gs4",
	"An4",
	"As4",
	"Bn4",
	"Cn5",
	"Cs5",
	"Dn5",
	"Ds5",
	"En5",
	"Fn5",
	"Fs5",
	"Gn5",
	"Gs5",
	"An5",
	"As5",
	"Bn5",
	"Cn6",
	"Cs6",
	"Dn6",
	"Ds6",
	"En6",
	"Fn6",
	"Fs6",
	"Gn6",
	"Gs6",
	"An6",
	"As6",
	"Bn6",
	"Cn7",
	"Cs7",
	"Dn7",
	"Ds7",
	"En7",
	"Fn7",
	"Fs7",
	"Gn7",
	"Gs7",
	"An7",
	"As7",
	"Bn7",
	"Cn8",
	"Cs8",
	"Dn8",
	"Ds8",
	"En8",
	"Fn8",
	"Fs8",
	"Gn8",
};

//Virtual Channel Structure
typedef struct {
    u8 sf;          //Status                //状态
                    /*声道状态的指示
                     * 当声音是停止时,是0
                     * 启动声音,设置其他参数,写入0x80到这里
                     * 停止声音,逻辑或0x40 释放按下(key-off),或者写一个零暂停,使用其他位是禁止的
                    */
    u8 ty;          //Type                  //类型
                    /*一个正常的声音,是0x00
                     * 如果音乐间隔是不计算和声音在高速计算则设置0x08
                     *
                     */
    u8 rv;          //Right Volume          //右声量
    u8 lv;          //Left Volume           //左声量
    u8 at;          //Attack                //按下的信号,声音开始,在0和1/60s 当它是255,一个过程的动作下一个衰减值
                    //敲击声音的时间   (255/x)*(1/60s),设置范围0-255
    u8 de;          //Decay                 //一个衰减值的信号,他由一个 value/256 每个1/60s,当到达过程是维持值,维持动作的状态
                    //衰减 (当前音量)*(x/256)每1/60s,如果小于或等于维持量,将维持现状
    u8 su;          //Sustain               //维持值的信号,这声音是由(实际 rv/256,lv/256 和输出左右)
                    //维持量设置
    u8 re;          //Release               //释放值的信号,key-off(逻辑或0x40在sf中)在state中,这个值是由 value/256 每 1/60s,这声道是完全停止
                    //释放 (当前音量)*(x/256)每1/60s,如果小于或等于伪回声的音量，它转移到伪回声状态。

    u8 r1[24];      // (reserved)      :    //(u32)r1[0x10]为数据大小
                    /*r[4] 伪回声的音量（[ 4 ]不是数量的元素，这是件#）
                     *r[5] 伪回声长度（[ 5 ]不是数量的元素，这是件#）
                     *
                     *
                     **r[0x10],波形大小?
                     *
                     * }
                     * 伪回声是一个可靠的固定量是一个固定的时间释放结束后剩余的。设置音量0-255和长度之间的0-127。时间的声音保持量长度乘以1 / 60秒。此外，如果您要使用的伪回声（体积！= 0），长度为计算下来，所以你需要再次设置它为每一个声音。
                     */
    u32 fr;         //Frequency Calculation Value   :0x20    //产生的频率的声音,写入midikey2freq的值在这里
                    //
    WaveData *wp;   //Wave Pointer
                    //指针到声音的波形数据。生成的波形数据可以自动从使用工具（aif2agb.exe AIFF文件），所以用户通常不需要自己创建它。
                    //这个设置指针的波形数据结构描述
    u32 r3[6];      // (reserved)           r3[0]当前声音数据偏移
} SoundChannel;

enum{
	soundchannel_stat_release = 0x40,	//当释放时
};

//parameter of gate+
#define	gtp1	1
#define	gtp2	2
#define	gtp3	3

//parameter of MODT, BRET
// vibrate
#define	mod_vib 0
// tremolo
#define	mod_tre 1
// auto-panpot
#define	mod_pan 2

//***
// parameter of MEMACC
//******************************************************@

	#define 	mem_set 0
	#define 	mem_add 1
	#define 	mem_sub 2
	#define 	mem_mem_set 3
	#define 	mem_mem_add 4
	#define 	mem_mem_sub 5
	#define 	mem_beq 6
	#define 	mem_bne 7
	#define 	mem_bhi 8
	#define 	mem_bhs 9
	#define 	mem_bls 10
	#define 	mem_blo 11
	#define 	mem_mem_beq 12
	#define 	mem_mem_bne 13
	#define 	mem_mem_bhi 14
	#define 	mem_mem_bhs 15
	#define 	mem_mem_bls 16
	#define 	mem_mem_blo 17

//@ SOUND_MODE_REVERB_SET
//声音模式混响设置
#define	reverb_set 0x80

#endif
